#ifndef _SHARP_LINKEDLIST_H
#define _SHARP_LINKEDLIST_H

#include "sharp-common.h"

/**
 * @file src/linkedlist.c
 */

typedef struct sharp_linkedlist_s sharp_linkedlist;

/**
 * Keeps track of a linked list.
 * Linked lists are doubly circularly linked.
 */
struct sharp_linkedlist_s {
    /** pointer to the data */
    void *data;
    /** pointer to the previous node */
    sharp_linkedlist *prev;
    /** pointer to the next node */
    sharp_linkedlist *next;
};

/**
 * Initialize a (circularly doubly) linked list.
 * @param list pointer to the pointer to a list
 *
 * Empty lists take no space after initialization, they're initialized to NULL
 * and space for them is allocated at a later point.  Currently always returns
 * true.
 */
bool sharp_linkedlist_init(sharp_linkedlist **list);


/**
 * Inserts a node at the beginning of a linked list.
 * @param list the list to add the node to
 * @param data the data to be inserted
 */
bool sharp_linkedlist_insert(sharp_linkedlist **list, void *data);

/**
 * Appends a node to the end of a linked list.
 * @param list the list to add the node to
 * @param data the data to be inserted
 */
bool sharp_linkedlist_append(sharp_linkedlist **list, void *data);

/**
 * Deletes a node.
 * @param list the list to operate on
 * @param node the node to delete
 * @param data pointer where to store the data contained by the node
 * @return true if deletion suceeded, false otherwise
 */
bool sharp_linkedlist_delete(sharp_linkedlist **list, sharp_linkedlist **node,
    void **data);

/**
 * Deletes the last element of a list.
 * @param list the list to operate on
 * @param node the node to delete
 * @param data the data contained by the node to be deleted
 * @return true if deletion suceeded, false otherwise
 */
bool sharp_linkedlist_delete_last(sharp_linkedlist **list,
    sharp_linkedlist **node, void **data);

/**
 * Destroys a linked list.
 * @param list the list to be deleted
 * @param destroy_data a function that can be used to free the node data
 *
 * free() is an acceptable cleaning function if you only use simple data types.
 */
bool sharp_linkedlist_destroy(sharp_linkedlist **list, 
    void (*destroy_data)(void *data));

/**
 * Iterates to the next node of a linked list.
 * @param list the list to be iterated over
 * @param next the curent node of the list. This gets changed to the next node
 *  of the list when called.
 *  if NULL, returns the list.
 *
 *  Returns false if on the last node. To clean up a list, use
 *  sharp_linkedlist_destroy() instead. If you call 
 *  sharp_linkedlist_delete(), make sure to check
 *  for its return value instead, since sharp_linkedlist_iter() will be caught
 *  in an infinite loop, as its iteration is continuously started with the next
 *  element being set to NULL by sharp_linkedlist_delete().
 */
bool sharp_linkedlist_iter(sharp_linkedlist *list, sharp_linkedlist **next);

/**
 * Returns true if the list is empty, false otherwise.
 * @param list the list to check
 */
bool sharp_linkedlist_isempty(sharp_linkedlist *list);

#endif /* _SHARP_LINKEDLIST_H */
